<?php

/**
 * Here is your custom functions.
 */

function  uuid()
{
	$chars = md5(uniqid(mt_rand(), true));
	$uuid = substr($chars, 0, 8) . '-'
		. substr($chars, 8, 4) . '-'
		. substr($chars, 12, 4) . '-'
		. substr($chars, 16, 4) . '-'
		. substr($chars, 20, 12);
	return $uuid;
}

/**
 * 转化文件大小
 */
function getSize($filesize)
{
	if ($filesize >= 1073741824) {
		//转成GB
		$filesize = round($filesize / 1073741824 * 100) / 100 . ' GB';
	} elseif ($filesize >= 1048576) {
		//转成MB
		$filesize = round($filesize / 1048576 * 100) / 100 . ' MB';
	} elseif ($filesize >= 1024) {
		//转成KB
		$filesize = round($filesize / 1024 * 100) / 100 . ' KB';
	} else {
		//不转换直接输出
		$filesize = $filesize . ' B';
	}
	return $filesize;
}

/**
 * 获取表字段
 *
 * @param $tableName
 *
 * @return array
 */
function getfields($model, $fields = true)
{
	$table = $model->getTable();
	$allow_column = \plugin\admin\app\common\Util::db()->select("desc `$table`");
	$allow_column = array_column($allow_column, 'Type', 'Field');
	if ($fields) {
		return array_keys($allow_column);
	} else {
		return $allow_column;
	}
}


function str2arr($str, $glue = ',', $limit = 0): array
{

	if (is_array($str)) {
		return $str;
	} else {
		if (is_string($str) && trim($str) === '') return [];
		if ($limit > 0) {
			return explode($glue, $str, $limit);
		} else {
			return explode($glue, $str);
		}
	}
}


function arr2str($str, $glue = ','): string
{
	if (is_array($str)) {
		return implode($glue, $str);
	} else {
		return $str;
	}
}

/**
 * 将设置值转为二进制键值数组，exp: 'a,b,c,d'转为[‘1’='a','2'=>'b','4'=>c,'d'=>8]
 * @param array|string $options
 */
function set2pos($options): array
{
	if (is_string($options)) $options = explode(',', $options);
	$arr = [];
	foreach ($options as $k => $v) {
		$arr[pow(2, $k)] = $v;
	}
	return $arr;
}


/**
 * 二进制数转多选值  exp: 13 转成 [1,4,8]
 * @param $value
 * @param array $options
 */
function pos2arr($value, $options): array
{
	$result = [];
	$i = 0;
	if (is_string($options)) $options = explode(',', $options);
	foreach ($options as $option) {
		$val = pow(2, $i);
		if ($val & $value) {
			$result[] = $val;
		}
		$i++;
	}
	return $result;
}

/**
 * 多选值转二进制数 exp: [1,4,8] 转成 13
 * @param array $options
 * @return int
 */
function arr2pos($options)
{
	if (!is_array($options)) {
		return $options;
	}
	$num = 0;
	foreach ($options as $option) {
		$num = $num | $option;
	}
	return $num;
}

/**
 * 将位置转成值 exp: [1,4,8] 转成 ['1'=>'a','4'=>'b','8'=>c]
 * @param $arr,$options
 * @return array
 */
function pos2val($arr, $options)
{
	if (is_int($arr)) $arr = pos2arr($arr, $options);
	$options = set2pos($options);
	$result = [];
	foreach ($arr as $v) {
		if (!empty($options[$v])) {
			$result[$v] = $options[$v];
		}
	}
	return $result;
}


function str2opt($tag): array
{
	$tag = str2arr($tag);
	$options = array_map(function ($v) {
		return ['label' => $v, 'value' => $v];
	}, $tag);
	return $options;
}


function txt2html($text)
{
	// 删除回车间的空格
	//$text = preg_replace('/(?<=\s)(?<=[^\r\n])\s+(?=[^\r\n])(?=\s)/', '', $text);
	// 将连续的换行符转换为一个换行符
	$text = preg_replace('/\n\s*\n/', "\n\n", $text);

	$text = str_replace('  ', '　', $text); // 将二个半角空格替换成一个全角  
	$text = htmlentities($text);
	// 返回 HTML 格式文本
	return nl2br($text);
}


//---------------查询处理----------------
//返回数组
function laoha_query($builder, $set = [], $model = null)
{
	$init = [
		'no_where' => 'password',  //不允许查询字段列表
		'select' => '',  //select语句
		'hidden' => '',	//不包括字段,与select相关,设置了select,就不用设置了	
		'with' => '',	//默认关联多个用|分隔 设置如下即可'user:id,name|cate:id,title,parent_id',
		'page_type' => 1,   //分页样式 0不分页，只取前per_page条记录 1正常分布 2简单分页 3树形 9不分页，所有记录
		'order_by' => '-id', //'-'表示desc排序
		'per_page' => 10,  //每页记录数
		'data_format' => '', //是否启用模型中输出转换 执行 model->data_format($data,$init['data_format']);
		'like_where' => 'title,content', //指定使用like查询的字段
		//以下项仅为不将参数归入where中
		'perPage' => '',      //amis专用
		'orderBy' => '',		//amis专用
		'orderDir' => '',		//amis专用
		'page' => 1,
	];

	$where = [];
	if (!empty($set)) {
		if (!empty($set['perPage'])) { //amis参数
			$init['per_page'] = $set['perPage'];
		}

		//echo $init['order_by'];
		$where = array_diff_key($set, $init);         //分解出where查询
		$set = array_intersect_key($set, $init);	 //分解出set
		$init = array_merge($init, $set);
		//echo $init['order_by'].'===';
		if (!empty($set['orderBy'])) {  //amis参数
			if (!empty($set['orderDir']) && $set['orderDir'] == 'desc') {
				$init['order_by'] = '-' . $set['orderBy'];
			} else {
				$init['order_by'] = $set['orderBy'];
			}
		} elseif (!empty(request()->input('order_by'))) {
			$init['order_by'] = request()->input('order_by');
		}
	}

	//$set完成使命

	$init['no_where'] = str2arr($init['no_where']);

	$init['like_where'] = str2arr($init['like_where']);
	$init['hidden'] = str2arr($init['hidden']);

	//query start
	if (!empty($init['select']))  $builder = $builder->select(str2arr($init['select']));

	if (!empty($init['with'])) {
		$with = str2arr($init['with'], '|');
		$builder = $builder->with($with);
	}

	$with_where = !empty($where['with_where']) && is_array($where['with_where']) ? $where['with_where'] : [];
	// $with_where的查询结构类似 $with_or[user][-]=has..,$with_where['cate']['id']=in,1,2,3,4...	
	unset($where['with_where']);
	$with_or = !empty($where['with_or']) && is_array($where['with_or']) ? $where['with_or'] : [];
	// $with_where的查询结构类似 $with_or[user][-]=has..,$with_or['cate']['id']=in,1,2,3,4...
	unset($where['with_or']);

	$builder = query_where($builder, $where, $init);
	//return json_ok($builder->toSql());
	if (!empty($with_where)) {
		foreach ($with_where as $k => $v) {
			if (isset($v['_'])) {             // _特殊字段，不指定字段
				switch ($v) {
					case 'has':
						$builder = $builder->has($k);
						break;
					case 'or_has':
						$builder = $builder->orHas($k);
						break;
					case 'not_has':
						$builder = $builder->doesntHave($k);
						break;
					case 'or_not_has':
						$builder = $builder->orDoesntHave($k);
						break;
					case 'with_count':
						$builder = $builder->withCount($k);
						break;
					default:
						break;
				}
				unset($v['_']);
			}
			$builder = $builder->whereHas($k, function ($query) use ($v) {
				$query = query_where($query, $v);
			});
		}
	}
	if (!empty($with_or)) {
		foreach ($with_or as $k => $v) {
			if (isset($v['_'])) {
				switch ($v) {
					case 'has':
						$builder = $builder->has($k);
						break;
					case 'or_has':
						$builder = $builder->orHas($k);
						break;
					case 'not_has':
						$builder = $builder->doesntHave($k);
						break;
					case 'or_not_has':
						$builder = $builder->orDoesntHave($k);
						break;
					case 'with_count':
						$builder = $builder->withCount($k);
						break;
					default:
						break;
				}
				unset($v['_']);
			}
			$builder = $builder->whereHas($k, function ($query) use ($v) {
				$query = query_where($query, $v);
			});
		}
	}

	$order = str2arr($init['order_by']);

	if (!empty($order)) {
		foreach ($order as $k => $v) {
			if (strpos($v, '-') === 0) {
				$builder = $builder->orderBy(ltrim($v, '-'), 'desc');
			} else {
				$builder = $builder->orderBy($v, 'asc');
			}
		}
	}
	//echo $builder->toSql();
	//echo PHP_EOL;
	$per_page = (int) $init['per_page'];
	if ($per_page > 500) $per_page = 500;
	if ($init['page_type'] == '2') {  //简单分布
		$builder = $builder->simplePaginate($per_page);
		//$hasNext = $builder->hasMorePages();
		//去队隐藏字段
		//$items = $init['hidden'] ? $builder->makeHidden(str2arr($init['hidden'])) : $builder;
		$items = $builder->toArray();
		if (!empty($items['data']) && !empty($init['hidden'])) {
			$hidden = $init['hidden'];
			$items['data'] = array_map(function ($val) use ($hidden) {
				foreach ($hidden as $f) {
					unset($val[$f]);
				}
				return $val;
			}, $items['data']);
		}

		if (!empty($items['data']) && !empty($init['data_format']) && !empty($model) && method_exists($model, 'data_format')) {
			foreach ($items['data'] as $k => $v) {
				$items['data'][$k] = $model->data_format($v, $init['data_format']);
			}
		}
		$items['items'] = $items['data'];
		unset($items['data']);
		$items['page'] = $items['current_page'];
		$items['hasNext'] = empty($items['next_page_url']) ? 0 : 1;
		$data = $items;
	} elseif ($init['page_type'] == '1') {  //正常分页
		$builder = $builder->paginate($per_page);

		$items = $builder->toArray();

		if (!empty($items['data']) && !empty($init['hidden'])) {
			$hidden = $init['hidden'];
			$items['data'] = array_map(function ($val) use ($hidden) {
				foreach ($hidden as $f) {
					unset($val[$f]);
				}
				return $val;
			}, $items['data']);
		}
		if (!empty($items['data']) && !empty($init['data_format']) && !empty($model) && method_exists($model, 'data_format')) {
			foreach ($items['data'] as $k => $v) {
				$items['data'][$k] = $model->data_format($v, $init['data_format']);
			}
		}

		$items['items'] = $items['data'];
		unset($items['data']);
		$items['page'] = $items['current_page'];
		$data = $items;
	} else {                            //不分页
		if ($init['page_type'] == '3' || $init['page_type'] == '9') {
			$builder = $builder->get();
		} else {
			$builder = $builder->limit($per_page)->get();
		}
		//$items = $init['hidden'] ? $builder->makeHidden(str2arr($init['hidden'])) : $builder;
		$items = $builder->toArray();
		if (!empty($init['hidden'])) {
			$hidden = $init['hidden'];
			$items = array_map(function ($val) use ($hidden) {
				foreach ($hidden as $f) {
					unset($val[$f]);
				}
				return $val;
			}, $items);
		}

		if (!empty($init['data_format']) && !empty($model) && method_exists($model, 'data_format')) {
			foreach ($items as $k => $v) {
				$items[$k] = $model->data_format($v, $init['data_format']);
				if (empty($items[$k])) {
					unset($items[$k]);
				}
			}
		}
		if ($init['page_type'] == '3') {
			$items = array2tree($items);
		}
		$data = $items;
	}

	return $data;
}

/*
$where 格式：array
同一字段多次操作用|分隔，每次操作时操作符用:分隔,值如果是数组用,分隔，再用str2arr()转为数组
[
	'字段1' => '操作符:值|值'，
	'字段2' => '值|操作符:值'，
	....
]
*/
function query_where($query, $where = [], $init = [])
{
	if (!is_array($where)) return $query;
	foreach ($where as $k => $v) {  //and和or是非正式字段名
		if(strpos($k,'_')===0) continue;      //以_开头字段不处理
		//如果字段在no_where中，跳出
		if (!empty($init['no_where']) && in_array($k, $init['no_where']))  continue;
		if ($k == 'query') {
			if (strpos($v, "|")) {        //function($query)方式查询，如aaa,0|bb,or,3|title,like,cc
				$query = $query->where(function ($query) use ($v, $init) {
					$v = str2arr($v, '|');
					foreach ($v as $vo) {
						$vo = str2arr($vo, ',', 2);
						$f = $vo[0];
						$query = query_field($query, $f, $vo[1], $init);
					}
				});
			}
		} elseif ($k == 'or_query') {
			if (strpos($v, "|")) {
				$query = $query->orWhere(function ($query) use ($v, $init) {
					$v = str2arr($v, '|');
					foreach ($v as $vo) {
						$vo = str2arr($vo, ',', 2);
						$f = $vo[0];
						$query = query_field($query, $f, $vo[1], $init);
					}
				});
			}
		} else {
			$query = query_field($query, $k, $v, $init);
		}
	}
	return $query;
}

function query_field($query, $field, $v, $init = [])
{
	if (is_array($v) || $v === null || $v == '') {
		return $query;
	}
	$f = [
		'between', 'not_between', 'in', 'not_in', 'not', 'or_not',
		'or', 'or_like', 'or_between', 'or_not_between', 'or_in', 'or_not_in',
		'date', 'year', 'day', 'month', 'time', 'json', 'or_json', 'json_length'
	];
	$fexp = ['gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'neq' => '<>', 'like' => 'like'];

	if (strpos($v, ",")) {
		$sarr = str2arr($v, ',', 2);
		$sarr[1] = trim($sarr[1]);
		if ($sarr[1] !== '' && in_array($sarr[0], array_merge($f, array_keys($fexp)))) {
			$varr = $sarr;
		}
	}
	/*
	if (strpos($field, ".")) {
		$field = str_replace('.', '->', $field);
	}*/
	//gt大于,lg小于 ge|>= le|<=
	if (!empty($varr)) {

		switch ($varr[0]) {
			case 'not':
				$query = $query->whereNot($field, $varr[1]);
				break;
			case 'between':
				$query = $query->whereBetween($field, str2arr($varr[1]));
				break;
			case 'not_between':
				$query = $query->whereNotBetween($field, str2arr($varr[1]));
				break;
			case 'in':
				$query = $query->whereIn($field, str2arr($varr[1]));
				break;
			case 'not_in':
				$query = $query->whereNotIn($field, str2arr($varr[1]));
				break;
			case 'or':
				if (strpos($varr[1], ",")) {
					$sa = str2arr($varr[1], ',', 2);
					$sa[1] = trim($sa[1]);
					if ($sa[1] !== '' && in_array($sa[0], array_keys($fexp))) {
						$varr[1] = $sa;
					}
				}
				if (is_array($varr[1])) {
					$query = $query->orWhere($field, $fexp[$sa[0]], $sa[1]);
				} else {
					$query = $query->orWhere($field, $varr[1]);
				}
				break;
			case 'or_not':
				$query = $query->orWhereNot($field, $varr[1]);
				break;
			case 'or_like':
				$query = $query->orWhere($field, 'like', '%' . $varr[1] . '%');
				break;
			case 'or_between':
				$query = $query->orWhereBetween($field, str2arr($varr[1]));
				break;
			case 'or_not_between':
				$query = $query->orWhereNotBetween($field, str2arr($varr[1]));
				break;
			case 'or_in':
				$query = $query->orWhereIn($field, str2arr($varr[1]));
				break;
			case 'or_not_in':
				$query = $query->orWhereNotIn($field, str2arr($varr[1]));
				break;

			case 'json':  //attaches.url,json,uploads/1/10/Image/2016-12-09/1481268001666015.jpg
				if (strpos($varr[1], ",")) {
					$varr[1] = str2arr($varr[1]);  //json,a.b,aa,bb,cc此方法是查询a->b的值为['aa','bb','cc']而不是wherein 
				}
				$query = $query->whereJsonContains($field, $varr[1]);
				break;
			case 'or_json':  //attaches.url,or_json,uploads/1/10/Image/2016-12-09/1481268001666015.jpg
				$query = $query->orWhereJsonContains($field, $varr[1]);
				break;
			case 'json_length':  //attaches.url,json_length,1
				if (strpos($varr[1], ",")) {
					$sa = str2arr($varr[1], ',', 2);
					$sa[1] = trim($sa[1]);
					if ($sa[1] !== '' && $sa[0] != 'like' && in_array($sa[0], array_keys($fexp))) {
						$query = $query->whereJsonLength($field, $fexp[$sa[0]], $sa[1]);
					}
				} else {
					$query = $query->whereJsonLength($field, $varr[1]);
				}
				break;

			case 'date':
				if (strpos($varr[1], ",")) {
					$va = str2arr($varr[1]);
					$query =  in_array($va[0], array_keys($fexp)) ?  $query->whereDate($field, $fexp[$va[0]], $va[1]) : $query;
				} else {
					$query = $query->whereDate($field, $varr[1]);
				}
				break;
			case 'month':    //'fieldname'=>'month,gt,3'
				if (strpos($varr[1], ",")) {
					$va = str2arr($varr[1]);
					$query =  in_array($va[0], array_keys($fexp)) ? $query->whereMonth($field, $fexp[$va[0]], $va[1]) : $query;
				} else {
					$query = $query->whereMonth($field, $varr[1]);
				}
				break;
			case 'day':
				if (strpos($varr[1], ",")) {
					$va = str2arr($varr[1]);
					$query =  in_array($va[0], array_keys($fexp)) ? $query->whereDay($field, $fexp[$va[0]], $va[1]) : $query;
				} else {
					$query = $query->whereDay($field, $varr[1]);
				}
				break;
			case 'year':
				if (strpos($varr[1], ",")) {
					$va = str2arr($varr[1]);
					$query =  in_array($va[0], array_keys($fexp)) ? $query->whereYear($field, $fexp[$va[0]], $va[1]) : $query;
				} else {
					$query = $query->whereYear($field, $varr[1]);
				}
				break;
			case 'time':
				if (strpos($varr[1], ",")) {
					$va = str2arr($varr[1]);
					$query = in_array($va[0], array_keys($fexp)) ? $query->whereTime($field, $fexp[$va[0]], $va[1]) : $query;
				} else {
					$query = $query->whereTime($field, $varr[1]);
				}
				break;
			default:
				if (in_array($varr[0], array_keys($fexp))) {
					if ($varr[0] == 'like') {
						$query = $query->where($field, $fexp[$varr[0]], '%' . $varr[1] . '%');
					} else {
						$query = $query->where($field, $fexp[$varr[0]], $varr[1]);
					}
				}
		}
	} else {
		switch ($v) {
			case 'null':
				$query = $query->whereNull($field)->orWhere($field, '');
				break;
			case 'not_null':
				$query = $query->whereNotNull($field)->where($field, '<>', '');
				break;
			default:
				if (!empty($init['like_where']) && in_array($field, $init['like_where'])) {
					$query = $query->where($field, 'like', '%' . $v . '%');
				} else {
					$query = $query->where($field, $v);
				}
		}
	}
	return $query;
}

//---------------查询处理结束----------------

//---------------分类及树形处理----------------


/**
 * 生成树状数据
 *
 * @param array $list
 * @param int $parentId
 *
 * @return array
 */
function array2tree(array $list, int $parentId = 0, int $level = 0)
{
	$data = [];
	$level = $level + 1;
	foreach ($list as $key => $item) {
		$item['level'] = $level;
		if ($item['parent_id'] == $parentId) {
			$children = array2tree($list, (int)$item['id'], $level);
			!empty($children) && $item['children'] = $children;
			$data[] = $item;
			unset($list[$key]);
		}
	}
	return $data;
}


/**
 * 生成树状数据后再扁平化
 *
 * @param array $tree //树状数据
 * @return array
 */
function tree2list(array $tree, $list = [], $pids = [], $cids = [])
{
	foreach ($tree as $key => $item) {
		$list[$item['id']] = $item;
		if (!empty($pids)) {
			$list[$item['id']]['pids'] = $pids;
		}

		if (!empty($item['children'])) {
			$list[$item['id']]['cids'] = array_merge($cids, array_column($item['children'], 'id'));
			foreach ($item['children'] as $k => $v) {
				$list = tree2list($item['children'], $list, array_merge($pids, [$item['id']]), $cids);
				if (!empty($v['children'])) {
					$list[$item['id']]['cids'] = array_merge($list[$item['id']]['cids'], $list[$v['id']]['cids']);
				}
			}
			if (!empty($cids[$item['id']])) {
				$list[$item['id']]['cids'] = $cids[$item['id']];
			}
			unset($list[$item['id']]['children']);
		}
	}
	return $list;
}


function laoha_thumb($url = '', $w = 200, $h = 200)
{
	if ($url) {
		$url = ltrim($url, '/');
		return "/thumb/" . $w . "x" . $h . "/" . $url;
	} else {
		return laoha_no_img($w, $h);
	}
}

function laoha_no_img($w = 0, $h = 0)
{
	$noimg = '/no.jpg';
	if (is_file(base_path() . '/plugin/laoha/public' . $noimg) && ($w || $h)) {
		return "/thumb/" . $w . "x" . $h . '/app/laoha' . $noimg;
	} else {
		return '';
	}
}


//去除分类选择中空目录,对select取得的$data过滤 $data = $this->filterCate($data)
function filter_cates($data = [])
{
	$arr = [];
	foreach ($data as $k => $v) {
		if (empty($v['is_publish'])) {
			if (!empty($v['children'])) {
				$sub = filter_cates($v['children']);
				if (!empty($sub)) {
					$v['children'] = $sub;
					$arr[] = $v;
				}
			}
		} else {
			if ($v['is_hidden']) {
				$v['title'] = '【隐】' . $v['title'];
			}
			$arr[] = $v;
		}
	}
	return $arr;
}

//时间转化
function timeTo($time)
{
	if(empty($time)) return '';
	$nowTime = time();
	$showTime = strtotime($time);
	$difference = $nowTime - $showTime;
	if ($difference < 0) {
		return $time;
	}
	if ($difference < 60) {
		return $difference . '秒前';
	}
	if ($difference < 3600) {
		return floor($difference / 60) . '分钟前';
	}
	if ($difference < 86400) {
		return floor($difference / 3600) . '小时前';
	}
	if ($difference < 2592000) {
		return floor($difference / 86400) . '天前'; //30天内
	}
	return date('Y-m-d H:i',strtotime($time));
}

//返回处理
function json_ok($data, $s = 3)
{
	$idata = [
		'status'            => 0,  //amis用
		'code'              => 0,
		'msg'               => 'ok',
		'msgTimeout' => $s * 1000,   //amis用		
		'data' => [],
	];

	if (is_string($data)) {
		$idata['msg'] = $data;
		$data = [];
	} elseif (!is_array($data)) {
		$data = (array) $data;
	}
	$idata['data'] = $data;
	return json($idata);
}

function json_fail($msg = 'fail', $s = 5)
{
	$idata = [
		'status'            => 1,
		'code'              => 1,
		'msg'               => 'fail',
		'msgTimeout' => $s * 1000,
	];
	$idata['msg'] = $msg;
	return json($idata);
}

function parsemd($str=''){
	$Parsedown = new \plugin\laoha\app\common\Parsedown();
	return $Parsedown->setSafeMode(true)->setBreaksEnabled(true)->text($str);	
}

/**
 * 打印数组或字符串
 */
function dd(String|Array|Float|Int $trage)
{
    $str = is_array($trage) ? var_export($trage,1) : trim($trage);
    $hears = ['Content-Type' => 'text/html;charset=utf-8'];
    return new \support\Response('200',$hears,'<pre>'.$str);
}

/**
 * 是否前台管理员
 *
 * @Author 老蟹 7040867@qq.com    DateTime 2023-11-25
 * @return boolean
 */
function is_manage(){
        //后台用户
        if (admin_id() && $roles = admin('roles')) {
            $rules = \plugin\admin\app\model\Role::whereIn('id', $roles)->pluck('rules')->toArray();
            if (in_array('*', $rules) || in_array('#', $rules)) {  //超级管理员
                return true;
            }
        }
		return false;	
}

//设置的数组必须是kv对,$v值如morphmaps,nav.roots,cate.roots ...
function plugin_config_merge($v=''){
	$arr = [];
	$plugins = array_keys(config('plugin'));
	foreach($plugins as $name){
		if($set = config('plugin.'.$name.'.set.'.$v,false)){
			if(is_array($set)){
				foreach($set as $k=>$s){
					$arr[$k]=$s;
				}
			}
		}
	} 
	return $arr;
}